using System;
using System.Text;
using System.Collections.Generic;
using My.IdlConverter.Core;
using My.IdlConverter.Core.Filters;

namespace My.IdlConverter.Com
{
    public class ComClassTemplate : ClassTemplate
    {
        private static readonly StringBuilder ClassTemplateSeg1 = new StringBuilder();
        private static readonly StringBuilder ClassTemplateSeg3 = new StringBuilder();
        private static readonly StringBuilder ClassTemplateSeg5 = new StringBuilder();
        private static readonly StringBuilder ClassTemplateSeg7 = new StringBuilder();

        public static readonly string ExtendsBaseClass = "	public ";
        public static readonly string IDispatchImp = "	public IDispatchImpl<I%TEMPLATE%, &IID_I%TEMPLATE%, &LIBID_MyFit, /*wMajor =*/ 1, /*wMinor =*/ 0>";
        public static readonly string ComInterfaceEntry = "		COM_INTERFACE_ENTRY(I%TEMPLATE%)";
        public static readonly string ComInterfaceEntry2 = "		COM_INTERFACE_ENTRY(IDispatch,I%TEMPLATE%)";
        public static readonly string ComInterfaceEntryIID = "		COM_INTERFACE_ENTRY_IID(IID_I%TEMPLATE%,I%TEMPLATE%)";
        public static readonly string ComInterfaceEntryChain = "		COM_INTERFACE_ENTRY_CHAIN(C%TEMPLATE%)";

        public StringBuilder this[int index]
        {
            get
            {
                switch (index)
                {
                    case 1:
                        return ClassTemplateSeg1;
                    case 3:
                        return ClassTemplateSeg3;
                    case 5:
                        return ClassTemplateSeg5;
                    case 7:
                        return ClassTemplateSeg7;
                    default:
                        {
                            System.Diagnostics.Debug.Assert(false);
                            break;
                        }
                }

                return null;
            }
        }

        public override void Reset()
        {
            ClassTemplateSeg1.Remove(0, ClassTemplateSeg1.Length);
            ClassTemplateSeg3.Remove(0, ClassTemplateSeg3.Length);
            ClassTemplateSeg5.Remove(0, ClassTemplateSeg5.Length);
            ClassTemplateSeg7.Remove(0, ClassTemplateSeg7.Length);
        }

        public override void Build(Class sourceClass)
        {
            Reset();
            //[seg1]
            ClassTemplateSeg1.AppendLine("#pragma once");
            ClassTemplateSeg1.AppendLine();

            ClassTemplateSeg1.AppendFormat("#include \"{0}.h\"{1}",Component.Name,Environment.NewLine);
            ClassTemplateSeg1.AppendLine("#include \"Initialization.h\"");
            IList<Class> baseClasses = new List<Class>();
            sourceClass.GetBaseClasses(ref baseClasses);
            if (baseClasses.Count != 0)
            {
                foreach (Class nextBaseClass in baseClasses)
                {
                    ClassTemplateSeg1.AppendLine(String.Format("#include \"{0}.h\"", ClassModifier.GetTitle(nextBaseClass)));
                }
            }
            ClassTemplateSeg1.AppendLine();

            ClassTemplateSeg1.AppendLine("class ATL_NO_VTABLE C%TEMPLATE% : ");

            if (!sourceClass.HasBaseClass && sourceClass.Depth <= 1)
                ClassTemplateSeg1.AppendLine("	public CComObjectRootEx<CComSingleThreadModel>,");

            if (sourceClass.IsFinal())
                ClassTemplateSeg1.AppendLine("	public CComCoClass<C%TEMPLATE%, &CLSID_%TEMPLATE%>,");

            //[seg2]
            //the interface inheritance will be added here.
            //CLASS_TEMPLATE.AppendLine("	public IDispatchImpl<IDocument, &IID_IDocument, &LIBID_MyFit, /*wMajor =*/ 1, /*wMinor =*/ 0>");

            //[seg3]
            ClassTemplateSeg3.AppendLine("{");
            ClassTemplateSeg3.AppendLine("public:");
            ClassTemplateSeg3.AppendLine("	C%TEMPLATE%(){}");

            ClassTemplateSeg3.AppendLine();
            if (!sourceClass.Abstract)
                ClassTemplateSeg3.AppendLine("	DECLARE_REGISTRY_RESOURCEID(IDR_%TEMPLATE_U%)");

            ClassTemplateSeg3.AppendLine();
            ClassTemplateSeg3.AppendLine("	BEGIN_COM_MAP(C%TEMPLATE%)");

            if (sourceClass.HasBaseClass)
            {
                if (sourceClass.DefaultBaseInterface != null)
                {
                    ClassTemplateSeg3.AppendLine(String.Format("		COM_INTERFACE_ENTRY2(IDispatch,{0})", InterfaceModifier.GetName(sourceClass.DefaultBaseInterface.Name)));
                }
            }

            //[seg4]
            //The interface map will be added here

            //[seg5]
            ClassTemplateSeg5.AppendLine("	END_COM_MAP()");
            ClassTemplateSeg5.AppendLine();
            ClassTemplateSeg5.AppendLine("	DECLARE_PROTECT_FINAL_CONSTRUCT()");
            ClassTemplateSeg5.AppendLine();
            ClassTemplateSeg5.AppendLine("	HRESULT FinalConstruct()");
            ClassTemplateSeg5.AppendLine("	{");
            ClassTemplateSeg5.AppendLine("		return S_OK;");
            ClassTemplateSeg5.AppendLine("	}");

            ClassTemplateSeg5.AppendLine();
            ClassTemplateSeg5.AppendLine("	void FinalRelease() ");
            ClassTemplateSeg5.AppendLine("	{");
            ClassTemplateSeg5.AppendLine("	}");

            //[seg6]
            //add methods here

            //[seg7]
            ClassTemplateSeg7.AppendLine("};");
            ClassTemplateSeg7.AppendLine();

            if (!sourceClass.Abstract)
                ClassTemplateSeg7.AppendLine("	OBJECT_ENTRY_AUTO(__uuidof(%TEMPLATE%),C%TEMPLATE%)");
        }
    }
}
